package org.eiahe.hr.sched;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ehe.business.timeout.domain.SsePushMessage;
import org.ehe.business.timeout.service.SsePushMessageService;
import org.ehe.common.core.constant.RoleKeyConstants;
import org.ehe.common.core.utils.StringUtils;
import org.ehe.common.satoken.utils.LoginHelper;
import org.ehe.common.sse.dto.SseMessageDto;
import org.ehe.common.sse.utils.SseMessageUtils;
import org.ehe.system.domain.vo.SysUserVo;
import org.ehe.system.service.ISysRoleService;
import org.ehe.system.service.ISysUserService;
import org.eiahe.hr.employeeRelation.domain.ContractInfo;
import org.eiahe.hr.employeeRelation.domain.vo.ContractInfoVo;
import org.eiahe.hr.employeeRelation.mapper.ContractInfoMapper;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 合同到期提醒定时任务
 *
 * @author zhangnn
 * @description 每天9点20检查合同到期情况，对于截止日期小于30天且未续签的合同进行提醒
 * @date 2025-11-05
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class ContractExpiryReminderTask {

    private final ContractInfoMapper contractInfoMapper;
    private final ScheduledExecutorService scheduledExecutorService;
    private final SsePushMessageService ssePushMessageService;
    private final ISysUserService userService;

    /**
     * 合同到期提醒定时任务
     * 每天9点20执行一次
     * cron表达式：0 20 9 * * ?
     */
    @Scheduled(cron = "0 20 9 * * ?")
    public void contractExpiryReminder() {
        try {
            log.info("=== 开始执行合同到期提醒任务 ===");
            Date today = DateUtil.beginOfDay(new Date()); // 今天0点
            Date thirtyDaysLater = DateUtil.endOfDay(DateUtil.offsetDay(today, 30)); // 30天后23:59:59

            // 查询所有未续签的合同
            LambdaQueryWrapper<ContractInfo> wrapper = Wrappers.lambdaQuery(ContractInfo.class)
                    .eq(ContractInfo::getRenewalStatus, "0") // 0表示未续签
                    .ge(ContractInfo::getExpiryDate, today)
                    .le(ContractInfo::getExpiryDate, thirtyDaysLater);

            List<ContractInfoVo> contractList = contractInfoMapper.selectVoList(wrapper);

            if (contractList.isEmpty()) {
                log.info("暂无需要提醒的合同");
                return;
            }

            Date now = new Date();
            int reminderCount = 0;

            for (ContractInfoVo contract : contractList) {
                if (contract.getExpiryDate() == null) {
                    continue;
                }

                // 计算合同到期天数
                long daysUntilExpiry = calculateDaysUntilExpiry(now, contract.getExpiryDate());

                // 如果合同截止日期小于30天，进行提醒
                if (daysUntilExpiry >= 0 && daysUntilExpiry <= 30) {
                    handleContractExpiryReminder(contract, daysUntilExpiry);
                    reminderCount++;
                }
            }

            log.info("=== 合同到期提醒任务完成，本次提醒 {} 份合同 ===", reminderCount);

        } catch (Exception e) {
            log.error("=== 合同到期提醒任务异常 ===", e);
        }
    }

    /**
     * 计算合同距离到期的天数
     *
     * @param now        当前日期
     * @param expiryDate 到期日期
     * @return 剩余天数
     */
    private long calculateDaysUntilExpiry(Date now, Date expiryDate) {
        return DateUtil.betweenDay(now, expiryDate, false);
    }

    /**
     * 处理合同到期提醒
     *
     * @param contract        合同信息
     * @param daysUntilExpiry 剩余天数
     */
    private void handleContractExpiryReminder(ContractInfoVo contract, long daysUntilExpiry) {
        log.warn("员工 [{}] 的合同将在 {} 天后到期，合同ID: {}，到期日期: {}",
                ObjectUtil.defaultIfNull(contract.getEmployeeName(), contract.getEmployeeNo()),
                daysUntilExpiry,
                contract.getContractId(),
                DateUtil.formatDate(contract.getExpiryDate()));

        // TODO: 可以在这里添加实际的提醒逻辑，比如：
        // 1. 发送邮件提醒
        // 2. 发送短信提醒
        // 3. 生成提醒记录到数据库
        // 4. 集成钉钉、企业微信等通知
        String msg = String.format(
            "员工 [%s] 的合同将在 %d 天后到期，合同ID: %s，到期日期: %s",
            ObjectUtil.defaultIfNull(contract.getEmployeeName(), contract.getEmployeeNo()),
            daysUntilExpiry,
            contract.getContractId(),
            DateUtil.formatDate(contract.getExpiryDate())
        );
        //用户ID
        List<Long> userIds = userService.selectUserIdsByRoleKey(RoleKeyConstants.HR_ROLES);
        //消息推送
        scheduledExecutorService.schedule(() -> {
            SseMessageDto dto = new SseMessageDto();
            dto.setMessage(msg);
            dto.setUserIds(userIds);
            SseMessageUtils.publishMessage(dto);
        }, 5, TimeUnit.SECONDS);

        savePushRecord(contract, msg,"hrm-contract", userIds);
    }

    /**
     * 保存推送记录
     * @param contract
     * @param msg
     * @param userIds
     */
    private void savePushRecord(ContractInfoVo contract, String msg, String type,List<Long> userIds) {
        //保存推送信息
        SsePushMessage pushMessage = new SsePushMessage();
        pushMessage.setInstanceId(contract.getContractId());
        pushMessage.setMessageType(type);
        pushMessage.setMessage(msg);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < userIds.size(); i++) {
            sb.append(userIds.get(i));
            // 最后一个元素后不添加逗号
            if (i != userIds.size() - 1) {
                sb.append(",");
            }
        }
        pushMessage.setUserIds(sb.toString());
        SysUserVo sysUserVo = userService.selectUserById(userIds.get(0));
        String tenantId = LoginHelper.getTenantId();
        if(StringUtils.isBlank(tenantId) && Objects.nonNull(sysUserVo)){
            tenantId = sysUserVo.getTenantId();
        }
        pushMessage.setTenantId(tenantId);
        ssePushMessageService.save(pushMessage);
    }
}
